#pragma once

#include <string>
#include <memory>
#include <functional>
#include <jsoncpp/json/json.h>

#include "InetAddr.hpp"
#include "Socket.hpp"

using namespace SocketModule;

class Request
{
public:

    Request() = default;

    Request(int x, int y, char oper)
        :_x(x)
        ,_y(y)
        ,_oper(oper)
    {
        ;
    }

    int getX() const
    {
        return _x;
    }

    int getY() const
    {
        return _y;
    }

    char getOper() const
    {
        return _oper;
    }

    std::string serialize()
    {
        Json::Value root;
        root["x"] = _x;
        root["y"] = _y;
        root["oper"] = _oper;

        Json::FastWriter writer;
        return writer.write(root);
    }

    bool deserialize(const std::string& str)
    {
        Json::Value root;
        Json::Reader reader;
        bool ok = reader.parse(str, root);
        if (ok == true)
        {
            _x = root["x"].asInt();
            _y = root["y"].asInt();
            _oper = root["oper"].asInt();
        }
        return ok;
    }

    ~Request()
    {
        ;
    }

private:

    int _x;
    int _y;
    char _oper;
};

class Response
{
public:

    Response() = default;

    Response(int infoCode, int result)
        :_infoCode(infoCode)
        ,_result(result)
    {
        ;
    }

    void setInfoCode(int infoCode)
    {
        _infoCode = infoCode;
    }

    void setResult(int result)
    {
        _result = result;
    }

    int getInfoCode() const
    {
        return _infoCode;
    }

    int getResult() const
    {
        return _result;
    }

    std::string serialize()
    {
        Json::Value root;
        root["infoCode"] = _infoCode;
        root["result"] = _result;

        Json::FastWriter writer;
        return writer.write(root);
    }

    bool deserialize(const std::string& str)
    {
        Json::Value root;
        Json::Reader reader;

        bool ok = reader.parse(str, root);
        if (ok == true)
        {
            _infoCode = root["infoCode"].asInt();
            _result = root["result"].asInt();
        }
        return ok;
    }

    ~Response()
    {
        ;
    }

private:

    int _infoCode;
    int _result;
};

const std::string separated = "\r\n";
using fun_t = std::function<Response(Request&)>;

class Protocol
{
public:

    Protocol(fun_t task)
        :_task(task)
    {
        ;
    }

    static std::string encode(const std::string& str)
    {
        return std::to_string(str.size()) + separated + str + separated;
    }

    static bool decode(std::string& str, std::string& package)
    {
        size_t pos = str.find(separated);
        if (pos == str.npos)
        {
            return false;
        }

        std::string lenSelf = str.substr(0, pos);
        size_t len = std::stoi(lenSelf);
        size_t oneInfoLen = len + separated.size() * 2 + lenSelf.size();
        if (str.size() < oneInfoLen)
        {
            return false;
        }

        package = str.substr(pos + separated.size(), len);
        str.erase(0, oneInfoLen);
        return true;
    }

    void getRequest(std::shared_ptr<Socket> sock, const InetAddr& client)
    {
        std::string message_package;
        while (true)
        {
            int len = sock->recv(message_package);
            if (len > 0)
            {
                std::string one_package; 
                if (decode(message_package, one_package) == false)  // 解码，还原一个信息
                {
                    continue;
                }
                
                Request req;
                if (req.deserialize(one_package) == false)          // 反序列
                {
                    continue;
                }

                Response res = _task(req);                          // 应用层执行
                LOG(LogLevel::DEBUG) << "client[" << client.getStringAddr() << "] " << "结果: " << res.getResult() << " 返回值: " << res.getInfoCode();

                std::string send_package = res.serialize();         // 序列化

                sock->send(encode(send_package));                   // 编码并发送
            }
            else if (len == 0)
            {
                LOG(LogLevel::DEBUG) << "client[" << client.getStringAddr() << "] quit";
                break;
            }
            else
            {
                LOG(LogLevel::WARNING) << "client[" << client.getStringAddr() << "] sock recv failure";
                break;
            }
        }
    }

    static bool getResponse(std::shared_ptr<Socket> sock, Response& res)
    {
        std::string req_buf;
        while (true)
        {
            int n = sock->recv(req_buf);

            if (n > 0)
            {
                std::string recv_info;
                if (Protocol::decode(req_buf, recv_info) == true)     
                {
                    return res.deserialize(recv_info);
                }

                return false;
            }
            else if (n == 0)
            {
                LOG(LogLevel::DEBUG) << "getResponse over";
                break;
            }
            else
            {
                LOG(LogLevel::WARNING) << "recv failure";
                break;
            }
        }
        return false;
    }

    static std::string buildRequestProtocolString(int x, int y, char oper)
    {
        Request req(x, y, oper);
        return encode(req.serialize());
    }

    ~Protocol()
    {
        ;
    }

private:

    fun_t _task;
};
